package com.hailiao.beidou.message.ui.page.chat

import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.paging.compose.LazyPagingItems
import androidx.paging.compose.collectAsLazyPagingItems
import com.d10ng.compose.ui.AppColor
import com.d10ng.compose.ui.AppShape
import com.d10ng.compose.ui.AppText
import com.d10ng.compose.ui.PageTransitions
import com.d10ng.compose.ui.base.Button
import com.d10ng.compose.ui.base.ButtonSize
import com.d10ng.compose.ui.base.ButtonType
import com.d10ng.compose.ui.navigation.NavBar
import com.d10ng.compose.view.Input
import com.hailiao.beidou.message.R
import com.hailiao.beidou.message.bd.Beidou
import com.hailiao.beidou.message.bd.constant.TextType
import com.hailiao.beidou.message.data.db.entity.MessageEntity
import com.hailiao.beidou.message.ui.page.chat.view.MessageListBox
import com.hailiao.beidou.message.ui.page.destinations.ContactDetailScreenDestination
import com.hailiao.beidou.message.ui.view.BDStatusBar
import com.hailiao.beidou.message.ui.view.NavBarIcon
import com.hailiao.beidou.message.utils.back
import com.hailiao.beidou.message.utils.go
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootNavGraph

/**
 * 聊天界面
 * @Author d10ng
 * @Date 2024/3/4 10:56
 */
@RootNavGraph
@Destination(
    style = PageTransitions::class,
    navArgsDelegate = ChatScreenNavArgs::class
)
@Composable
fun ChatScreen(
    model: ChatScreenViewModel = viewModel()
) {
    val hasContact by model.hasContactFlow.collectAsState(false)
    val name by model.nameFlow.collectAsState("")
    val messages = model.messagesFlow.collectAsLazyPagingItems()
    val input by model.inputFlow.collectAsState("")
    val type by model.typeFlow.collectAsState(TextType.CODE)
    val count by model.countFlow.collectAsState(0)
    val maxCount by model.maxCountFlow.collectAsState(0)

    // 使用lifecycle监听的方式，才能知道页面没有跳转而是直接回到了系统桌面
    // 而普通的DisposableEffect监听不到
    val lifecycleOwner = LocalLifecycleOwner.current
    val lifecycleObserver = remember {
        LifecycleEventObserver { _, event ->
            when (event) {
                Lifecycle.Event.ON_STOP -> {
                    model.onDispose()
                }
                Lifecycle.Event.ON_START -> {
                    model.onLaunch()
                }
                else -> Unit
            }
        }
    }

    LaunchedEffect(lifecycleOwner) {
        lifecycleOwner.lifecycle.addObserver(lifecycleObserver)
    }

    DisposableEffect(lifecycleOwner) {
        onDispose {
            lifecycleOwner.lifecycle.removeObserver(lifecycleObserver)
        }
    }

    ChatScreenView(
        initPosition = model.initPosition,
        hasContact = hasContact,
        name = name,
        messages = messages,
        input = input,
        type = type,
        count = count,
        maxCount = maxCount,
        onUpdateInput = model::onUpdateInput,
        onClickContact = {
            go(ContactDetailScreenDestination(model.number).route)
        },
        onClickMessageLocation = model::onClickMessageLocation,
        onClickSendLocation = {
            model.onClickSendLocation()
        },
        onClickSend = {
            model.onClickSend()
        }
    )
}

@Composable
private fun ChatScreenView(
    initPosition: Int = 0,
    hasContact: Boolean,
    name: String,
    messages: LazyPagingItems<MessageEntity>,
    input: String,
    type: TextType,
    count: Int,
    maxCount: Int,
    onUpdateInput: (String) -> Unit = {},
    onClickContact: () -> Unit = {},
    onClickMessageLocation: (MessageEntity.Location) -> Unit = {},
    onClickSendLocation: () -> Unit = {},
    onClickSend: () -> Unit = {},
) {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .background(AppColor.Neutral.bg)
            .navigationBarsPadding()
    ) {
        NavBar(
            title = name,
            titleAlignment = Alignment.CenterStart,
            onClickBack = { back() }
        ) {
            if (hasContact) {
                NavBarIcon(iconId = R.drawable.nav_contact, onClick = onClickContact)
            }
        }
        BDStatusBar()
        MessageListBox(
            initPosition = initPosition,
            name = name,
            messages = messages,
            onClickMessageLocation = onClickMessageLocation,
        )
        BottomBar(
            input = input,
            type = type,
            count = count,
            maxCount = maxCount,
            onUpdateInput = onUpdateInput,
            onClickSendLocation = onClickSendLocation,
            onClickSend = onClickSend
        )
    }
}

@Composable
private fun BottomBar(
    input: String,
    type: TextType,
    count: Int,
    maxCount: Int,
    onUpdateInput: (String) -> Unit = {},
    onClickSendLocation: () -> Unit = {},
    onClickSend: () -> Unit = {},
) {
    Column(
        modifier = Modifier
            .fillMaxWidth()
            .background(Color.White)
            .padding(19.dp, 12.dp)
            .imePadding()
    ) {
        Row(
            modifier = Modifier.fillMaxWidth(),
            verticalAlignment = Alignment.CenterVertically
        ) {
            Text(
                text = "自动选择类型：${type.text}",
                style = AppText.Normal.Tips.mini
            )
            Text(
                text = buildAnnotatedString {
                    withStyle(style = SpanStyle(color = AppColor.Func.error)) {
                        append("$count")
                    }
                    withStyle(style = SpanStyle(color = AppColor.Neutral.tips)) {
                        append("/${maxCount}字节")
                    }
                },
                style = AppText.Normal.Tips.mini,
                modifier = Modifier
                    .weight(1f)
                    .padding(start = 9.dp),
                textAlign = TextAlign.End
            )
        }
        Row(
            modifier = Modifier
                .padding(top = 12.dp)
                .fillMaxWidth(),
            verticalAlignment = Alignment.Bottom
        ) {
            // 键盘控制器
            val keyboardController = LocalSoftwareKeyboardController.current
            // 发送位置按钮
            Image(
                painter = painterResource(id = R.drawable.message_send_location),
                contentDescription = null,
                modifier = Modifier
                    .padding(end = 8.dp)
                    .size(37.dp)
                    .background(AppColor.Neutral.bg, AppShape.RC.Cycle)
                    .clip(AppShape.RC.Cycle)
                    .clickable(onClick = {
                        onClickSendLocation()
                        keyboardController?.hide()
                    })
                    .padding(8.dp),
                contentScale = ContentScale.FillBounds
            )
            // 输入框
            Input(
                value = input,
                onValueChange = onUpdateInput,
                textStyle = AppText.Normal.Title.default,
                placeholder = "请输入您的信息...",
                placeholderStyle = AppText.Normal.Tips.default.copy(Color(0xFFAFAFAF)),
                maxLines = 5,
                modifier = Modifier
                    .weight(1f)
                    .defaultMinSize(minHeight = 37.dp)
                    .background(AppColor.Neutral.bg, AppShape.RC.v6)
                    .border(1.dp, AppColor.Neutral.line, AppShape.RC.v6)
                    .padding(12.dp, 7.dp)
            )

            if (input.isNotEmpty()) {
                val bdStatus by Beidou.statusFlow.collectAsState()
                val wait by Beidou.waitTimeFlow.collectAsState()
                val lessLength = remember(count, maxCount) {
                    maxCount - count
                }
                val buttonDisable =
                    remember(bdStatus, wait, lessLength) {
                        val needWait = wait > 0
                        val needConnect = bdStatus.isConnected.not()
                        val needLessInput = lessLength < 0
                        needWait || needConnect || needLessInput
                    }
                val buttonText = remember(wait) {
                    if (wait > 0) "($wait)" else "发送"
                }
                Button(
                    text = buttonText,
                    type = ButtonType.PRIMARY,
                    size = ButtonSize.SMALL,
                    shape = AppShape.RC.v6,
                    onClick = onClickSend,
                    disabled = buttonDisable,
                    modifier = Modifier.padding(start = 12.dp),
                )
            }
        }
    }
}